<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  
  
  <meta name="description" content="如今微信是个简洁并且功能强大的社交App，那么微信撤回消息的功能究竟是如何实现的呢，撤回的消息我们能不能查看呢，今天78行代码实现微信撤回消息查看   —Python itchat
123456下面就使用itchat做一个这样的程序：私聊撤回的信息可以收集起来并发送到个人微信的文件助手，包括：(1)" />
  

  
  
  
  
  
  
  <title>消息撤回 | 南辞的技术博客</title>
  <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
  <meta name="description" content="如今微信是个简洁并且功能强大的社交App，那么微信撤回消息的功能究竟是如何实现的呢，撤回的消息我们能不能查看呢，今天78行代码实现微信撤回消息查看   —Python itchat 123456下面就使用itchat做一个这样的程序：私聊撤回的信息可以收集起来并发送到个人微信的文件助手，包括：(1) who ：谁发送的(2) when ：什么时候发送的消息(3) what：什么信息(4) whic">
<meta property="og:type" content="article">
<meta property="og:title" content="消息撤回">
<meta property="og:url" content="https://yanlidoushikeke.gitee.io/myhexo/2021/03/23/%E6%B6%88%E6%81%AF%E6%92%A4%E5%9B%9E/index.html">
<meta property="og:site_name" content="南辞的技术博客">
<meta property="og:description" content="如今微信是个简洁并且功能强大的社交App，那么微信撤回消息的功能究竟是如何实现的呢，撤回的消息我们能不能查看呢，今天78行代码实现微信撤回消息查看   —Python itchat 123456下面就使用itchat做一个这样的程序：私聊撤回的信息可以收集起来并发送到个人微信的文件助手，包括：(1) who ：谁发送的(2) when ：什么时候发送的消息(3) what：什么信息(4) whic">
<meta property="og:locale" content="en_US">
<meta property="article:published_time" content="2021-03-23T08:54:49.000Z">
<meta property="article:modified_time" content="2021-03-23T09:18:49.747Z">
<meta property="article:author" content="南辞">
<meta name="twitter:card" content="summary">
  
  
    <link rel="icon" href="/tefuir/css/images/favicon.ico">
  
  
<link rel="stylesheet" href="/tefuir/css/style.css">

  

  
  <!-- baidu webmaster push -->
  <script src='//push.zhanzhang.baidu.com/push.js'></script>
<meta name="generator" content="Hexo 5.2.0"><link rel="alternate" href="/tefuir/atom.xml" title="南辞的技术博客" type="application/atom+xml">
</head>
<body class="home blog custom-background custom-font-enabled single-author">
  <div id="page" class="hfeed site">
      <header id="masthead" class="site-header" role="banner">
    <hgroup>
      <h1 class="site-title">
        <a href="/tefuir/" title="南辞的技术博客" rel="home">南辞的技术博客</a>
      </h1>
      
        <h2 class="site-description hitokoto"></h2>
        <script type="text/javascript" src="https://v1.hitokoto.cn/?encode=js"></script>
      
    </hgroup>

    <nav id="site-navigation" class="main-navigation" role="navigation">
            <button class="menu-toggle">菜单</button>
            <a class="assistive-text" href="/#content" title="跳至内容">跳至内容</a><!--TODO-->
            <div class="menu-main-container">
                <ul id="menu-main" class="nav-menu">
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/tefuir/">Home</a></li>
                
                    <li class="menu-item menu-item-type-post_type menu-item-object-page"><a href="/tefuir/archives">Archives</a></li>
                
                </ul>
            </div>
    </nav>
</header>

      <div id="main" class="wrapper">
        <div id="primary" class="site-content"><div id="content" role="main"><article id="post-消息撤回" class="post-消息撤回 post type-post status-publish format-standard hentry">
    <!---->

      <header class="entry-header">
        
        
  
    <h1 class="entry-title article-title">
      消息撤回
    </h1>
  

        
        <div class="comments-link">
            
            <a href="javascript:void(0);" data-url="https://yanlidoushikeke.gitee.io/myhexo/2021/03/23/%E6%B6%88%E6%81%AF%E6%92%A4%E5%9B%9E/" data-id="ckmlt5cd30000bku06svu8aan" class="leave-reply bdsharebuttonbox" data-cmd="more">Share</a>
        </div><!-- .comments-link -->
      </header><!-- .entry-header -->

    <div class="entry-content">
      
        <p>如今微信是个简洁并且功能强大的社交App，那么微信撤回消息的功能究竟是如何实现的呢，撤回的消息我们能不能查看呢，今天78行代码实现微信撤回消息查看   —Python itchat</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">下面就使用itchat做一个这样的程序：</span><br><span class="line">私聊撤回的信息可以收集起来并发送到个人微信的文件助手，包括：</span><br><span class="line">(1) who ：谁发送的</span><br><span class="line">(2) when ：什么时候发送的消息</span><br><span class="line">(3) what：什么信息</span><br><span class="line">(4) which：哪一类信息，包括：文本、图片、语音、视频、分享、位置、附件</span><br></pre></td></tr></table></figure>

<h4 id="代码实现"><a href="#代码实现" class="headerlink" title="代码实现"></a>代码实现</h4><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br><span class="line">103</span><br><span class="line">104</span><br><span class="line">105</span><br><span class="line">106</span><br><span class="line">107</span><br><span class="line">108</span><br><span class="line">109</span><br><span class="line">110</span><br></pre></td><td class="code"><pre><span class="line"># -*-encoding:utf-8-*-</span><br><span class="line">import os</span><br><span class="line">import re</span><br><span class="line">import shutil</span><br><span class="line">import time</span><br><span class="line">import itchat</span><br><span class="line">from itchat.content import *</span><br><span class="line"></span><br><span class="line"># 说明：可以撤回的有文本文字、语音、视频、图片、位置、名片、分享、附件</span><br><span class="line"></span><br><span class="line"># &#123;msg_id:(msg_from,msg_to,msg_time,msg_time_rec,msg_type,msg_content,msg_share_url)&#125;</span><br><span class="line">msg_dict &#x3D; &#123;&#125;</span><br><span class="line"></span><br><span class="line"># 文件存储临时目录</span><br><span class="line">rev_tmp_dir &#x3D; &quot;&#x2F;home&#x2F;alic&#x2F;RevDir&#x2F;&quot;</span><br><span class="line">if not os.path.exists(rev_tmp_dir): os.mkdir(rev_tmp_dir)</span><br><span class="line"></span><br><span class="line"># 表情有一个问题 | 接受信息和接受note的msg_id不一致 巧合解决方案</span><br><span class="line">face_bug &#x3D; None</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 将接收到的消息存放在字典中，当接收到新消息时对字典中超时的消息进行清理 | 不接受不具有撤回功能的信息</span><br><span class="line"># [TEXT, PICTURE, MAP, CARD, SHARING, RECORDING, ATTACHMENT, VIDEO, FRIENDS, NOTE]</span><br><span class="line">@itchat.msg_register([TEXT, PICTURE, MAP, CARD, SHARING, RECORDING, ATTACHMENT, VIDEO])</span><br><span class="line">def handler_receive_msg(msg):</span><br><span class="line">    global face_bug</span><br><span class="line">    # 获取的是本地时间戳并格式化本地时间戳 e: 2017-04-21 21:30:08</span><br><span class="line">    msg_time_rec &#x3D; time.strftime(&quot;%Y-%m-%d %H:%M:%S&quot;, time.localtime())</span><br><span class="line">    # 消息ID</span><br><span class="line">    msg_id &#x3D; msg[&#39;MsgId&#39;]</span><br><span class="line">    # 消息时间</span><br><span class="line">    msg_time &#x3D; msg[&#39;CreateTime&#39;]</span><br><span class="line">    # 消息发送人昵称 | 这里也可以使用RemarkName备注　但是自己或者没有备注的人为None</span><br><span class="line">    msg_from &#x3D; (itchat.search_friends(userName&#x3D;msg[&#39;FromUserName&#39;]))[&quot;NickName&quot;]</span><br><span class="line">    # 消息内容</span><br><span class="line">    msg_content &#x3D; None</span><br><span class="line">    # 分享的链接</span><br><span class="line">    msg_share_url &#x3D; None</span><br><span class="line">    if msg[&#39;Type&#39;] &#x3D;&#x3D; &#39;Text&#39; \</span><br><span class="line">            or msg[&#39;Type&#39;] &#x3D;&#x3D; &#39;Friends&#39;:</span><br><span class="line">        msg_content &#x3D; msg[&#39;Text&#39;]</span><br><span class="line">    elif msg[&#39;Type&#39;] &#x3D;&#x3D; &#39;Recording&#39; \</span><br><span class="line">            or msg[&#39;Type&#39;] &#x3D;&#x3D; &#39;Attachment&#39; \</span><br><span class="line">            or msg[&#39;Type&#39;] &#x3D;&#x3D; &#39;Video&#39; \</span><br><span class="line">            or msg[&#39;Type&#39;] &#x3D;&#x3D; &#39;Picture&#39;:</span><br><span class="line">        msg_content &#x3D; r&quot;&quot; + msg[&#39;FileName&#39;]</span><br><span class="line">        # 保存文件</span><br><span class="line">        msg[&#39;Text&#39;](rev_tmp_dir + msg[&#39;FileName&#39;])</span><br><span class="line">    elif msg[&#39;Type&#39;] &#x3D;&#x3D; &#39;Card&#39;:</span><br><span class="line">        msg_content &#x3D; msg[&#39;RecommendInfo&#39;][&#39;NickName&#39;] + r&quot; 的名片&quot;</span><br><span class="line">    elif msg[&#39;Type&#39;] &#x3D;&#x3D; &#39;Map&#39;:</span><br><span class="line">        x, y, location &#x3D; re.search(</span><br><span class="line">            &quot;&lt;location x&#x3D;\&quot;(.*?)\&quot; y&#x3D;\&quot;(.*?)\&quot;.*label&#x3D;\&quot;(.*?)\&quot;.*&quot;, msg[&#39;OriContent&#39;]).group(1, 2, 3)</span><br><span class="line">        if location is None:</span><br><span class="line">            msg_content &#x3D; r&quot;纬度-&gt;&quot; + x.__str__() + &quot; 经度-&gt;&quot; + y.__str__()</span><br><span class="line">        else:</span><br><span class="line">            msg_content &#x3D; r&quot;&quot; + location</span><br><span class="line">    elif msg[&#39;Type&#39;] &#x3D;&#x3D; &#39;Sharing&#39;:</span><br><span class="line">        msg_content &#x3D; msg[&#39;Text&#39;]</span><br><span class="line">        msg_share_url &#x3D; msg[&#39;Url&#39;]</span><br><span class="line">    face_bug &#x3D; msg_content</span><br><span class="line">    # 更新字典</span><br><span class="line">    msg_dict.update(</span><br><span class="line">        &#123;</span><br><span class="line">            msg_id: &#123;</span><br><span class="line">                &quot;msg_from&quot;: msg_from, &quot;msg_time&quot;: msg_time, &quot;msg_time_rec&quot;: msg_time_rec,</span><br><span class="line">                &quot;msg_type&quot;: msg[&quot;Type&quot;],</span><br><span class="line">                &quot;msg_content&quot;: msg_content, &quot;msg_share_url&quot;: msg_share_url</span><br><span class="line">            &#125;</span><br><span class="line">        &#125;</span><br><span class="line">    )</span><br><span class="line"></span><br><span class="line"></span><br><span class="line"># 收到note通知类消息，判断是不是撤回并进行相应操作</span><br><span class="line">@itchat.msg_register([NOTE])</span><br><span class="line">def send_msg_helper(msg):</span><br><span class="line">    global face_bug</span><br><span class="line">    if re.search(r&quot;\&lt;\!\[CDATA\[.*撤回了一条消息\]\]\&gt;&quot;, msg[&#39;Content&#39;]) is not None:</span><br><span class="line">        # 获取消息的id</span><br><span class="line">        old_msg_id &#x3D; re.search(&quot;\&lt;msgid\&gt;(.*?)\&lt;\&#x2F;msgid\&gt;&quot;, msg[&#39;Content&#39;]).group(1)</span><br><span class="line">        old_msg &#x3D; msg_dict.get(old_msg_id, &#123;&#125;)</span><br><span class="line">        if len(old_msg_id) &lt; 11:</span><br><span class="line">            itchat.send_file(rev_tmp_dir + face_bug, toUserName&#x3D;&#39;filehelper&#39;)</span><br><span class="line">            os.remove(rev_tmp_dir + face_bug)</span><br><span class="line">        else:</span><br><span class="line">            msg_body &#x3D; &quot;告诉你一个秘密~&quot; + &quot;\n&quot; \</span><br><span class="line">                       + old_msg.get(&#39;msg_from&#39;) + &quot; 撤回了 &quot; + old_msg.get(&quot;msg_type&quot;) + &quot; 消息&quot; + &quot;\n&quot; \</span><br><span class="line">                       + old_msg.get(&#39;msg_time_rec&#39;) + &quot;\n&quot; \</span><br><span class="line">                       + &quot;撤回了什么 ⇣&quot; + &quot;\n&quot; \</span><br><span class="line">                       + r&quot;&quot; + old_msg.get(&#39;msg_content&#39;)</span><br><span class="line">            # 如果是分享存在链接</span><br><span class="line">            if old_msg[&#39;msg_type&#39;] &#x3D;&#x3D; &quot;Sharing&quot;: msg_body +&#x3D; &quot;\n就是这个链接➣ &quot; + old_msg.get(&#39;msg_share_url&#39;)</span><br><span class="line"></span><br><span class="line">            # 将撤回消息发送到文件助手</span><br><span class="line">            itchat.send(msg_body, toUserName&#x3D;&#39;filehelper&#39;)</span><br><span class="line">            # 有文件的话也要将文件发送回去</span><br><span class="line">            if old_msg[&quot;msg_type&quot;] &#x3D;&#x3D; &quot;Picture&quot; \</span><br><span class="line">                    or old_msg[&quot;msg_type&quot;] &#x3D;&#x3D; &quot;Recording&quot; \</span><br><span class="line">                    or old_msg[&quot;msg_type&quot;] &#x3D;&#x3D; &quot;Video&quot; \</span><br><span class="line">                    or old_msg[&quot;msg_type&quot;] &#x3D;&#x3D; &quot;Attachment&quot;:</span><br><span class="line">                file &#x3D; &#39;@fil@%s&#39; % (rev_tmp_dir + old_msg[&#39;msg_content&#39;])</span><br><span class="line">                itchat.send(msg&#x3D;file, toUserName&#x3D;&#39;filehelper&#39;)</span><br><span class="line">                os.remove(rev_tmp_dir + old_msg[&#39;msg_content&#39;])</span><br><span class="line">            # 删除字典旧消息</span><br><span class="line">            msg_dict.pop(old_msg_id)</span><br><span class="line"></span><br><span class="line"></span><br><span class="line">if __name__ &#x3D;&#x3D; &#39;__main__&#39;:</span><br><span class="line">    itchat.auto_login(hotReload&#x3D;True,enableCmdQR&#x3D;2)</span><br><span class="line">    itchat.run()</span><br></pre></td></tr></table></figure>

<p>该程序可以直接在终端运行，在终端扫码成功够即可登录成功，同时也可以打包在window系统运行(注意修改一下路径，推荐使用相对路径。</p>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">➜  ~ python wx.py</span><br><span class="line">Getting uuid of QR code.</span><br><span class="line">Downloading QR code.</span><br><span class="line">Please scan the QR code to log in.</span><br><span class="line">Please press confirm on your phone.</span><br><span class="line">Loading the contact, this may take a little while.</span><br><span class="line">�[3;J</span><br><span class="line">Login successfully as AlicFeng</span><br><span class="line">Start auto replying.</span><br></pre></td></tr></table></figure>

<h4 id="tchat"><a href="#tchat" class="headerlink" title="tchat"></a>tchat</h4><p>简介<br>itchat是一个开源的微信个人号接口，使用python调用微信变得非常简单。简单是用itchat代码即可构建一个基于微信的即时通讯，更不错的体现在于方便扩展个人微信的在其他平台的更多通讯功能。</p>
<ul>
<li>安装</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip3 install itchat</span><br></pre></td></tr></table></figure>

<ul>
<li>itchat - Helloworld<br>仅仅三行代码发送一条信息给文件助手</li>
</ul>
<figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">import itchat</span><br><span class="line">itchat.auto_login(hotReload&#x3D;True)</span><br><span class="line">itchat.send(&#39;Hello AlicFeng&#39;, toUserName&#x3D;&#39;filehelper&#39;)</span><br></pre></td></tr></table></figure>

<ul>
<li>查看客户端</li>
</ul>

      
    </div><!-- .entry-content -->

    <footer class="entry-meta">
    <a href="/tefuir/2021/03/23/%E6%B6%88%E6%81%AF%E6%92%A4%E5%9B%9E/">
    <time datetime="2021-03-23T08:54:49.000Z" class="entry-date">
        2021-03-23
    </time>
</a>
    
    
    </footer>
</article>


    
<nav class="nav-single">
    <h3 class="assistive-text">文章导航</h3>
    
        <span class="nav-previous"><a href="/tefuir/2021/03/24/%E8%BF%9B%E5%BA%A6%E6%9D%A1/" rel="prev"><span class="meta-nav">←</span> 进度条</a></span>
    
    
        <span class="nav-next"><a href="/tefuir/2021/03/22/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" rel="next">设计模式 <span class="meta-nav">→</span></a></span>
    
</nav><!-- .nav-single -->







</div></div>
        <div id="secondary" class="widget-area" role="complementary">
  
    <aside id="search" class="widget widget_search"><form role="search" method="get" accept-charset="utf-8" id="searchform" class="searchform" action="//google.com/search">
    <div>
        <input type="text" value="" name="s" id="s" />
        <input type="submit" id="searchsubmit" value="搜索" />
    </div>
</form></aside>
  
    
  
    
  
    
  <aside class="widget">
    <h3 class="widget-title">Recents</h3>
    <div class="widget-content">
      <ul>
        
          <li>
            <a href="/tefuir/2021/04/26/python%E5%9F%BA%E7%A1%80%E7%90%86%E8%AE%BA%E5%AE%9D%E5%85%B8/">python基础理论宝典</a>
          </li>
        
          <li>
            <a href="/tefuir/2021/04/23/python3-Flask%E7%BB%93%E5%90%88Socket-io%E7%AE%80%E5%8D%95%E5%AE%9E%E7%8E%B0%E5%9C%A8%E7%BA%BF%E5%AE%A2%E6%9C%8D%E7%B3%BB%E7%BB%9F/">python3+Flask结合Socket.io简单实现在线客服系统</a>
          </li>
        
          <li>
            <a href="/tefuir/2021/04/23/win10%E7%B3%BB%E7%BB%9F%E4%B8%8B%E5%88%A9%E7%94%A8docker%E9%83%A8%E7%BD%B2gunicorn-Flask%E6%89%93%E9%80%A0%E7%8B%AC%E7%AB%8B%E9%95%9C%E5%83%8F/">win10系统下利用docker部署gunicorn+Flask打造独立镜像</a>
          </li>
        
          <li>
            <a href="/tefuir/2021/04/23/win10%E7%B3%BB%E7%BB%9F%E4%B8%8B%E5%9F%BA%E4%BA%8Edocker%E9%85%8D%E7%BD%AEelasticsearch%E9%85%8D%E5%90%88python3%E8%BF%9B%E8%A1%8C%E5%85%A8%E6%96%87%E6%A3%80%E7%B4%A2/">win10系统下基于docker配置elasticsearch配合python3进行全文检索</a>
          </li>
        
          <li>
            <a href="/tefuir/2021/04/23/%E6%9C%8D%E5%8A%A1%E5%99%A8%E9%97%AE%E9%A2%98/">服务器问题</a>
          </li>
        
      </ul>
    </div>
  </aside>

  
    
  
    
  
</div>
      </div>
      <footer id="colophon" role="contentinfo">
    <p>&copy; 2021 南辞
    All rights reserved.</p>
    <p>Powered by <a href="http://hexo.io/" target="_blank">Hexo</a></p>
</footer>
    <script>window._bd_share_config={"common":{"bdSnsKey":{},"bdText":"","bdMini":"1","bdMiniList":false,"bdPic":"","bdStyle":"2","bdSize":"16"},"share":{}};with(document)0[(getElementsByTagName('head')[0]||body).appendChild(createElement('script')).src='/js/share.js'];</script>

<script src="/js/jquery-3.3.1.min.js"></script>


  
<link rel="stylesheet" href="/tefuir/fancybox/jquery.fancybox.css">

  
<script src="/tefuir/fancybox/jquery.fancybox.pack.js"></script>




<script src="/tefuir/js/script.js"></script>


<script src="/js/navigation.js"></script>

<div id="bg"></div>

  </div>
</body>
</html>